package com.geek.bams.server;

import com.geek.bams.entity.Account;
import com.geek.bams.exception.*;
import com.geek.bams.service.Bank;

import java.io.*;
import java.net.Socket;


public class ServerTasker extends Thread {
    
    private Socket socket;
    private ATMServer server;
    private Bank bank;
    private ClientInfo clientInfo; // 客户端信息
    
    // 输入输出流
    private ObjectInputStream objectIn;
    private ObjectOutputStream objectOut;
    
    // 标记是否正在等待命令响应（用于区分命令响应和推送消息）
    private volatile boolean waitingForResponse = false;
    
    public ServerTasker(Socket socket, ATMServer server, ClientInfo clientInfo) {
        this.socket = socket;
        this.server = server;
        this.clientInfo = clientInfo;
        this.bank = Bank.getInstance(); // 获取Bank单例
    }
    
    @Override
    public void run() {
        try {
            // 使用ObjectInputStream/ObjectOutputStream统一处理所有数据，避免流冲突
            // 重要：必须先创建ObjectOutputStream并flush，确保头部信息被写入
            // 然后再创建ObjectInputStream，避免死锁
            objectOut = new ObjectOutputStream(socket.getOutputStream());
            objectOut.flush(); // 立即刷新，确保头部信息被写入
            objectIn = new ObjectInputStream(socket.getInputStream());
            
            Object receivedObject;
            // 持续读取客户端发送的命令（现在命令也是通过ObjectInputStream发送的）
            while ((receivedObject = objectIn.readObject()) != null) {
                // 检查接收到的对象类型
                if (!(receivedObject instanceof String)) {
                    server.appendLog("收到非字符串命令，类型：" + receivedObject.getClass().getName());
                    continue;
                }
                
                String command = (String) receivedObject;
                waitingForResponse = true;
                server.appendLog("收到客户端命令：" + command);
                
                // 解析命令并处理
                Object result = processCommand(command);
                
                // 将结果序列化后发送给客户端
                objectOut.writeObject(result);
                objectOut.flush();
                
                waitingForResponse = false;
                server.appendLog("已向客户端发送响应");
            }
            
        } catch (java.io.EOFException e) {
            // 客户端正常关闭连接
            server.appendLog("客户端断开连接");
        } catch (IOException e) {
            server.appendLog("处理客户端请求时出错：" + e.getMessage());
        } catch (ClassNotFoundException e) {
            server.appendLog("接收到的对象类型未知：" + e.getMessage());
        } catch (Exception e) {
            server.appendLog("未知错误：" + e.getMessage());
            try {
                // 发送错误信息给客户端
                if (objectOut != null) {
                    objectOut.writeObject("服务器内部错误：" + e.getMessage());
                    objectOut.flush();
                }
            } catch (IOException ioException) {
                server.appendLog("发送错误信息失败：" + ioException.getMessage());
            }
        } finally {
            // 关闭资源
            closeResources();
        }
    }
    
    /**
     * 处理客户端命令
     * @param command 命令字符串，格式：命令类型#参数1#参数2#...
     * @return 处理结果（Account对象或String错误信息）
     */
    private Object processCommand(String command) {
        try {
            // 使用"#"分割命令
            String[] parts = command.split("#");
            if (parts.length == 0) {
                return "命令格式错误：命令不能为空";
            }
            
            String cmdType = parts[0];
            
            switch (cmdType) {
                case "login":
                    return handleLogin(parts);
                    
                case "register":
                    return handleRegister(parts);
                    
                case "deposit":
                    return handleDeposit(parts);
                    
                case "withdraw":
                    return handleWithdraw(parts);
                    
                case "transfer":
                    return handleTransfer(parts);
                    
                case "requestLoan":
                    return handleRequestLoan(parts);
                    
                case "payLoan":
                    return handlePayLoan(parts);
                    
                case "updateCeiling":
                    return handleUpdateCeiling(parts);
                    
                case "getAccount":
                    return handleGetAccount(parts);
                    
                default:
                    return "未知命令：" + cmdType;
            }
            
        } catch (Exception e) {
            return "处理命令时出错：" + e.getMessage();
        }
    }
    
    /**
     * 处理登录命令：login#id#password
     */
    private Object handleLogin(String[] parts) {
        if (parts.length != 3) {
            return "登录命令格式错误：应为 login#id#password";
        }
        
        try {
            Long id = Long.parseLong(parts[1]);
            String password = parts[2];
            
            // 检查该账户是否已经在其他客户端登录
            ClientInfo existingClient = server.getClientByAccountId(id);
            if (existingClient != null && existingClient.isLoggedIn()) {
                // 如果当前客户端就是已登录的客户端，允许登录（可能是重连）
                if (existingClient != clientInfo) {
                    // 账户已在其他客户端登录，拒绝登录
                    server.appendLog("账户 " + id + " 已在其他客户端登录，拒绝重复登录");
                    return "该账户已在其他客户端登录，请先退出其他客户端！";
                }
            }
            
            Account account = bank.login(id, password);
            // 通知服务器客户端登录成功
            if (account != null && server != null) {
                // 如果账户已在其他地方登录，先断开旧连接
                if (existingClient != null && existingClient != clientInfo) {
                    ServerTasker oldTasker = server.getTaskerByAccountId(id);
                    if (oldTasker != null) {
                        try {
                            // 通知旧客户端账户已在其他地方登录
                            oldTasker.sendForceLogoutNotification();
                        } catch (Exception e) {
                            server.appendLog("通知旧客户端失败：" + e.getMessage());
                        }
                    }
                    // 从映射中移除旧连接
                    server.clientDisconnected(existingClient);
                }
                server.clientLoggedIn(clientInfo, account, this);
            }
            return account; // 返回Account对象表示成功
            
        } catch (NumberFormatException e) {
            return "账户ID格式错误";
        } catch (LoginException e) {
            return e.getMessage(); // 返回错误信息字符串
        } catch (Exception e) {
            return "登录失败：" + e.getMessage();
        }
    }
    
    /**
     * 处理注册命令：register#password#repassword#name#personID#email#type
     */
    private Object handleRegister(String[] parts) {
        if (parts.length != 7) {
            return "注册命令格式错误：应为 register#password#repassword#name#personID#email#type";
        }
        
        try {
            String password = parts[1];
            String repassword = parts[2];
            String name = parts[3];
            String personID = parts[4];
            String email = parts[5];
            int type = Integer.parseInt(parts[6]);
            
            Account account = bank.register(password, repassword, name, personID, email, type);
            return account; // 返回Account对象表示成功
            
        } catch (NumberFormatException e) {
            return "账户类型格式错误";
        } catch (RegisterException | LoginException | TypeException e) {
            return e.getMessage(); // 返回错误信息字符串
        } catch (Exception e) {
            return "注册失败：" + e.getMessage();
        }
    }
    
    /**
     * 处理存款命令：deposit#id#money
     */
    private Object handleDeposit(String[] parts) {
        if (parts.length != 3) {
            return "存款命令格式错误：应为 deposit#id#money";
        }
        
        try {
            Long id = Long.parseLong(parts[1]);
            double money = Double.parseDouble(parts[2]);
            
            Account account = bank.deposit(id, money);
            return account; // 返回更新后的Account对象
            
        } catch (NumberFormatException e) {
            return "参数格式错误";
        } catch (LoginException e) {
            return e.getMessage();
        } catch (Exception e) {
            return "存款失败：" + e.getMessage();
        }
    }
    
    /**
     * 处理取款命令：withdraw#id#password#money
     */
    private Object handleWithdraw(String[] parts) {
        if (parts.length != 4) {
            return "取款命令格式错误：应为 withdraw#id#password#money";
        }
        
        try {
            Long id = Long.parseLong(parts[1]);
            String password = parts[2];
            double money = Double.parseDouble(parts[3]);
            
            Account account = bank.withdraw(id, password, money);
            return account; // 返回更新后的Account对象
            
        } catch (NumberFormatException e) {
            return "参数格式错误";
        } catch (LoginException | BalanceNotEnoughException e) {
            return e.getMessage();
        } catch (Exception e) {
            return "取款失败：" + e.getMessage();
        }
    }
    
    /**
     * 处理转账命令：transfer#fromId#password#toId#money
     */
    private Object handleTransfer(String[] parts) {
        if (parts.length != 5) {
            return "转账命令格式错误：应为 transfer#fromId#password#toId#money";
        }
        
        try {
            Long fromId = Long.parseLong(parts[1]);
            String password = parts[2];
            Long toId = Long.parseLong(parts[3]);
            double money = Double.parseDouble(parts[4]);
            
            boolean success = bank.transfer(fromId, password, toId, money);
            if (success) {
                // 转账成功，返回更新后的转出账户
                Account account = bank.login(fromId, password);
                
                // 通知接收转账的账户客户端刷新（如果在线）
                ServerTasker toTasker = server.getTaskerByAccountId(toId);
                if (toTasker != null) {
                    // 异步发送刷新通知，避免阻塞当前响应
                    new Thread(() -> {
                        try {
                            // 等待一小段时间，确保当前响应已发送
                            Thread.sleep(100);
                            toTasker.sendRefreshNotification();
                            server.appendLog("已通知账户 " + toId + " 刷新账户信息");
                        } catch (Exception e) {
                            server.appendLog("通知账户刷新失败：" + e.getMessage());
                        }
                    }).start();
                }
                
                return account;
            } else {
                return "转账失败";
            }
            
        } catch (NumberFormatException e) {
            return "参数格式错误";
        } catch (LoginException | BalanceNotEnoughException | TransferException e) {
            return e.getMessage();
        } catch (Exception e) {
            return "转账失败：" + e.getMessage();
        }
    }
    
    /**
     * 处理贷款命令：requestLoan#id#money
     */
    private Object handleRequestLoan(String[] parts) {
        if (parts.length != 3) {
            return "贷款命令格式错误：应为 requestLoan#id#money";
        }
        
        try {
            Long id = Long.parseLong(parts[1]);
            double money = Double.parseDouble(parts[2]);
            
            Account account = bank.requestLoan(id, money);
            return account; // 返回更新后的Account对象
            
        } catch (NumberFormatException e) {
            return "参数格式错误";
        } catch (LoginException | LoanException | TypeException e) {
            return e.getMessage();
        } catch (Exception e) {
            return "贷款失败：" + e.getMessage();
        }
    }
    
    /**
     * 处理还款命令：payLoan#id#money
     */
    private Object handlePayLoan(String[] parts) {
        if (parts.length != 3) {
            return "还款命令格式错误：应为 payLoan#id#money";
        }
        
        try {
            Long id = Long.parseLong(parts[1]);
            double money = Double.parseDouble(parts[2]);
            
            Account account = bank.payLoan(id, money);
            return account; // 返回更新后的Account对象
            
        } catch (NumberFormatException e) {
            return "参数格式错误";
        } catch (LoginException | LoanException | TypeException e) {
            return e.getMessage();
        } catch (Exception e) {
            return "还款失败：" + e.getMessage();
        }
    }
    
    /**
     * 处理设置透支额度命令：updateCeiling#id#password#money
     */
    private Object handleUpdateCeiling(String[] parts) {
        if (parts.length != 4) {
            return "设置透支额度命令格式错误：应为 updateCeiling#id#password#money";
        }
        
        try {
            Long id = Long.parseLong(parts[1]);
            String password = parts[2];
            double money = Double.parseDouble(parts[3]);
            
            Account account = bank.updateCeiling(id, password, money);
            return account; // 返回更新后的Account对象
            
        } catch (NumberFormatException e) {
            return "参数格式错误";
        } catch (LoginException | TypeException e) {
            return e.getMessage();
        } catch (Exception e) {
            return "设置透支额度失败：" + e.getMessage();
        }
    }
    
    /**
     * 处理获取账户信息命令：getAccount#id#password
     */
    private Object handleGetAccount(String[] parts) {
        if (parts.length != 3) {
            return "获取账户命令格式错误：应为 getAccount#id#password";
        }
        
        try {
            Long id = Long.parseLong(parts[1]);
            String password = parts[2];
            
            Account account = bank.login(id, password);
            return account; // 返回Account对象
            
        } catch (NumberFormatException e) {
            return "账户ID格式错误";
        } catch (LoginException e) {
            return e.getMessage();
        } catch (Exception e) {
            return "获取账户信息失败：" + e.getMessage();
        }
    }
    
    /**
     * 发送刷新通知给客户端
     */
    public void sendRefreshNotification() {
        try {
            if (objectOut != null && socket != null && !socket.isClosed()) {
                objectOut.writeObject("REFRESH_ACCOUNT");
                objectOut.flush();
            }
        } catch (IOException e) {
            server.appendLog("发送刷新通知失败：" + e.getMessage());
        }
    }
    
    /**
     * 发送强制登出通知给客户端
     */
    public void sendForceLogoutNotification() {
        try {
            if (objectOut != null && socket != null && !socket.isClosed()) {
                objectOut.writeObject("FORCE_LOGOUT");
                objectOut.flush();
            }
        } catch (IOException e) {
            server.appendLog("发送强制登出通知失败：" + e.getMessage());
        }
    }
    
    /**
     * 发送服务器关闭通知给客户端
     */
    public void sendServerShutdownNotification() {
        try {
            if (objectOut != null && socket != null && !socket.isClosed()) {
                objectOut.writeObject("SERVER_SHUTDOWN");
                objectOut.flush();
            }
        } catch (IOException e) {
            // 服务器关闭时忽略错误
        }
    }
    
    /**
     * 关闭资源
     */
    private void closeResources() {
        try {
            // 通知服务器客户端断开连接
            if (server != null && clientInfo != null) {
                server.clientDisconnected(clientInfo);
            }
            
            if (objectOut != null) {
                objectOut.close();
            }
            if (objectIn != null) {
                objectIn.close();
            }
            if (socket != null && !socket.isClosed()) {
                socket.close();
            }
        } catch (IOException e) {
            if (server != null) {
                server.appendLog("关闭资源时出错：" + e.getMessage());
            }
        }
    }
}

